using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Security;
using System.Data.Odbc;
using System.Security.Principal;
using System.Reflection;

namespace MyPublisher.PublishService
{
    public static class ServiceManager
    {
        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
        public struct SERVICE_DESCRIPTION
        {
            [FieldOffset(0)]
            public string description;
        }

        #region Constants
        public static readonly UInt32 MaxLogSize = 2 * 1024 * 1024;
        public static readonly UInt32 MaxLogBackup = 5;
        public static readonly UInt32 MAXPATH = 512;
        public static readonly IntPtr NullPtr = (IntPtr)0;
        public static readonly int ThrdJoinDelay = 60000;	// 60 seconds
        public static readonly string ServiceName = "CA MM Directory Updater";
        public static readonly UInt32 SC_MANAGER_ALL_ACCESS = 0x000F003F;
        public static readonly UInt32 SERVICE_WIN32_OWN_PROCESS = 0x00000010;
        public static readonly UInt32 SERVICE_DEMAND_START = 0x00000003;
        public static readonly UInt32 SERVICE_ERROR_NORMAL = 0x00000001;
        public static readonly UInt32 SERVICE_CONFIG_DESCRIPTION = 0x00000001;
        #endregion

        #region interop
        [DllImport("Advapi32.dll", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr OpenSCManager(string machineName, string databaseName, UInt32 desiredAccess);

        [DllImport("Advapi32.dll", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr CreateService(IntPtr hSCManager, string serviceName, string displayName, UInt32 desiredAccess,
            UInt32 serviceType, UInt32 startType, UInt32 errorControl, string binaryPathName, string loadOrderGroup, IntPtr tagID,
            string dependencies, string serviceStartName, string password);

        [DllImport("Advapi32.dll", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern IntPtr OpenService(IntPtr hSCManager, string serviceName, UInt32 desiredAccess);

        [DllImport("Advapi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool DeleteService(IntPtr hService);

        [DllImport("Advapi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CloseServiceHandle(IntPtr hService);

        [DllImport("Advapi32.dll", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool ChangeServiceConfig2(IntPtr hService, uint infoLevel, ref SERVICE_DESCRIPTION info);

        [DllImport("Kernel32.dll", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern UInt32 GetLastError();
        #endregion

        #region method
        public static bool RegisterService(string service_name, string service_description, string exec_path)
        {
            return ServiceManager.RegisterService(service_name, service_name, service_description, exec_path);
        }
        public static bool RegisterService(string service_name, string display_service_name, string service_description, string exec_path)
        {
            IntPtr hSCM, hService;
            UInt32 err;
            hSCM = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
            if (NullPtr == hSCM)
            {
                return false;
            }

            hService = CreateService(hSCM, service_name, display_service_name, SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, exec_path, null, NullPtr, null, null, null);

            if (NullPtr == hService)
            {
                err = GetLastError();
                CloseServiceHandle(hSCM);
                return false;
            }

            if (service_description != "")
            {
                SERVICE_DESCRIPTION desc = new SERVICE_DESCRIPTION();
                desc.description = service_description;
                ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, ref desc);
            }
            CloseServiceHandle(hService);
            CloseServiceHandle(hSCM);
            return true;
        }
        public static bool RemoveService(string service_name)
        {
            IntPtr hSCM, hService;
            bool ret;

            hSCM = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
            if (NullPtr == hSCM)
                return false;

            hService = OpenService(hSCM, service_name, SC_MANAGER_ALL_ACCESS);
            if (NullPtr == hService)
            {
                CloseServiceHandle(hSCM);
                return false;
            }

            ret = DeleteService(hService);

            CloseServiceHandle(hService);
            CloseServiceHandle(hSCM);

            return ret;
        }
        #endregion
    }
}
